% SUBJECT: Professional GEM, Appendix B
% 13.11.90
%

\subsection{Folder {\tt $\backslash$rest}}
\nopagebreak

\subsubsection{\tt gmcl15.c}
\begin{verbatim} 
/*------------------------------*/
/*      includes                */
/*------------------------------*/

#include "portab.h"     /* portable coding conv */
#include "machine.h"    /* machine depndnt conv */
#include "osbind.h"     /* BDOS defintions      */
#include "gemdefs.h"

/*------------------------------*/
/*      open_file               */
/*------------------------------*/
        WORD
open_file(file_name)
        BYTE    *file_name;
        {
        LONG    dos_hndl;

        FOREVER
                {
                dos_hndl = Fopen(file_name, 0);
                if (dos_hndl >= 0)
                        return ((WORD) dos_hndl);
                if ( !dos_error((WORD) dos_hndl) )
                        return (-1);
                }

        return (-1);            /* Appease lint */
        }

/*------------------------------*/
/*      create_file             */
/*------------------------------*/
        WORD
create_file(file_name)
        BYTE    *file_name;
        {
        LONG    dos_hndl;

        FOREVER
                {
                dos_hndl = Fcreate(file_name, 0);
                if (dos_hndl >= 0)
                        return ((WORD) dos_hndl);
                if ( !dos_error((WORD) dos_hndl) )
                        return (-1);
                }

        return (-1);            /* Appease lint */
        }

/*------------------------------*/
/*      dos_error               */
/*------------------------------*/
        WORD
dos_error(tos_err)
        WORD    tos_err;
        {
        WORD    f_ret;

        graf_mouse(ARROW, 0x0L);
        if (tos_err > -50)
                {
                tos_err += 31;
                tos_err = -tos_err;
                }
        f_ret = form_error(tos_err);
        return (f_ret);
        }

/*------------------------------*/
/*      get_file                */
/*------------------------------*/
        WORD
get_file(extnt, got_file)
        BYTE    *extnt, *got_file;
        {
        WORD    butn, ii;
        BYTE    tmp_path[64], tmp_name[13];

        tmp_name[0] = '\0';
        tmp_path[0] = '\0';

        if (*got_file)
                parse_fname(got_file, tmp_path,
                            tmp_name, extnt);
        if (!tmp_path[0])
                get_path(&tmp_path[0], extnt);

        fsel_input(tmp_path, tmp_name, &butn);
        if (butn)
                {
                strcpy(got_file, tmp_path);
                for (ii = 0;
                     got_file[ii] && got_file[ii] != '*';
                     ii++)
                    ;
                got_file[ii - 1] = '\0';
                strcat (got_file, "\\");
                strcat(got_file, tmp_name);
                return (TRUE);
                }
        else
                return (FALSE);
        }

/*------------------------------*/
/*      parse_fname             */
/*------------------------------*/
        VOID
parse_fname(full, path, name, extnt)
        BYTE    *full, *path, *name, *extnt;
        {
        WORD    i, j;
        BYTE    *s, *d;

        /* scan for end of path */
        for (i = strlen(full); i--; )   
                if (full[i] == '\\' || full[i] == ':')
                        break;
        if (i == -1)
                strcpy(name, full); /* "Naked" file name */
        else
                {
                strcpy(name, &full[i+1]);
                for (s = full, d = path, j = 0; j++ < i + 1;
                        *d++ = *s++);
                strcpy(&path[i+1], "*.");
                strcat(path, extnt);
                }
        }

/*------------------------------*/
/*      get_path                */
/*------------------------------*/
        VOID
get_path(tmp_path, spec)
        BYTE    *tmp_path, *spec;
        {
        WORD    cur_drv;

        cur_drv = Dgetdrv();
        tmp_path[0] = cur_drv + 'A';
        tmp_path[1] = ':';
        Dgetpath(&tmp_path[2], 0);
        if (strlen(tmp_path) > 3)
                strcat(tmp_path, "\\");
        else
                tmp_path[2] = '\0';
        strcat(tmp_path, "*.");
        strcat(tmp_path, spec);
        }

/*------------------------------*/
/*      new_ext                 */
/*------------------------------*/
        VOID
new_ext(o_fname, n_fname, ext)
        BYTE    *o_fname, *n_fname, *ext;
        {
        WORD    ii, jj;

        strcpy(n_fname, o_fname);
        for (ii =  (jj = strlen(n_fname)) - 1;
             ii && n_fname[ii] != '.';
             ii--)
           ;

        if (!ii)
                n_fname[ii = jj] = '.';
        strcpy(&n_fname[++ii], ext);
        }


\end{verbatim}
\newpage

\subsubsection{\tt gmcl16.c}
\begin{verbatim} 

>>>>>>>>>> Progress box setup and cleanup <<<<<<<<<<<<<<<<

/*------------------------------*/
/*      beg_prog                */
/*------------------------------*/
        VOID
beg_prog(rect)
        GRECT   *rect;
        {
        OBJECT  *tree;
        WORD    xdial, ydial, wdial, hdial;

        rsrc_gaddr(R_TREE, PROGRESS, &tree);

        form_center(tree, &rect->g_x, &rect->g_y,
                          &rect->g_w, &rect->g_h);

        form_dial(0, 0, 0, 0, 0,
                  rect->g_x, rect->g_y, 
                  rect->g_w, rect->g_h);

        objc_draw(tree, ROOT, MAX_DEPTH,
                  rect->g_x, rect->g_y, 
                  rect->g_w, rect->g_h);
        }

/*------------------------------*/
/*      end_prog                */
/*------------------------------*/
        VOID
end_prog(rect)
        GRECT   *rect;
        {
        form_dial(3, 0, 0, 0, 0,
                  rect->g_x, rect->g_y,
                  rect->g_w, rect->g_h);
        }

>>>>>>>>>>>>> Text line progress indicator <<<<<<<<<<<<<<<

/*------------------------------*/
/*      set_prog                */
/*------------------------------*/
        VOID
set_prog(strno)
        UWORD   strno;
        {
        OBJECT  *tree;
        BYTE    *saddr;

        rsrc_gaddr(R_TREE, STRINGS, &tree);
        saddr = (BYTE *) (tree + strno)->ob_spec;
        rsrc_gaddr(R_TREE, PROGRESS, &tree);
        set_text(tree, PLINE, saddr);
        disp_obj(tree, PLINE);
        }


>>>>>>>>>>> Moving bar progress indicator <<<<<<<<<<<<<<<

/*------------------------------*/
/*      set_prog                */
/*------------------------------*/
        VOID
set_prog(value, maxc)
        WORD    value, maxc;
        {
        WORD    wnew, wold;
        OBJECT  *tree;
        GRECT   box;

        rsrc_gaddr(R_TREE, PROGRESS, &tree);
        /* Take border into account */
        wold = (tree + PROBOX)->ob_width - 1;
        wnew = wold + 1;
        if (maxc)
                wnew = max(1, ( (LONG) value *
                                (LONG) wnew) /
                                 maxc ); 
        (tree + PROBAR)->ob_width = wnew;
        if (value)
                {
                objc_xywh(tree, PROBAR, &box);
                box.g_x += wold; box.g_w -= wold;
                objc_draw(tree, ROOT, MAX_DEPTH,
                          box.g_x, box.g_y, 
                          box.g_w, box.g_h);
                }
        }       

>>>>>>>> Progress indicator check for abort <<<<<<<<<<<
        
/*------------------------------*/
/*      esc_prog                */
/*------------------------------*/
        WORD
esc_prog()
        {
        WORD    which, kr;
        WORD    mx, my, mb, ks, br; /* Not used, but needed */

        FOREVER 
                {
                which = evnt_multi(MU_KEYBD | MU_TIMER,
                        0, 0, 0,
                        0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0,
                        0L, 
                        0, 0, /* Zero timer delay */
                        &mx, &my, &mb, &ks, &kr, &br);

                if (which & MU_KEYBD)
                        {
                        /* ESC?           */
                        if ((kr & 0xff) == 0x1B)
                                return (TRUE);
                        /* else try again */
                        }
                else /* if (which & MU_TIMER) */
                        return (FALSE);
                }

        return (TRUE);  /* Keeps lint happy */ 
        }

>>>>>>>>>>>>> Progress subroutines  <<<<<<<<<<<<<<<<

        VOID
set_text(tree, obj, str)
        OBJECT  *tree;
        BYTE    *str;
        WORD    obj;
        {
        TEDINFO *obspec;

        /* Get TEDINFO address  */
        obspec = (TEDINFO *) (tree + obj)->ob_spec;

        /* Set new text pointer */
        obspec->te_ptext = str;

        /* Set new length       */
        obspec->te_txtlen = strlen(str);
        }

        VOID
disp_obj(tree, obj)
        OBJECT  *tree;
        WORD    obj;
        {
        GRECT   box;

        objc_xywh(tree, obj, &box);
        objc_draw(tree, ROOT, MAX_DEPTH,
                  box.g_x, box.g_y, 
                  box.g_w, box.g_h);
        }


/* get x,y,w,h for specified object */

        VOID
objc_xywh(tree, obj, p)
        OBJECT  *tree;
        WORD    obj;
        GRECT   *p;
        {
        objc_offset(tree, obj, &p->g_x, &p->g_y);
        p->g_w = (tree + obj)->ob_width;
        p->g_h = (tree + obj)->ob_height;
        }

>>>>>>>>>>>> Box mover examples <<<<<<<<<<<<<<<<<<<<<

/*------------------------------*/
/*      fourway_box             */
/*------------------------------*/
        VOID
fourway_box(vdi_handle, rubber, limit)
        WORD    vdi_handle;
        GRECT   *rubber, *limit;
        {
        UWORD   ox, oy, mx, my, foo, down;

        /* Set VDI modes for box */
        vswr_mode(vdi_handle, MD_XOR);          
        vsl_color(vdi_handle, BLACK);

        /* Capture mouse         */
        wind_update(BEG_MCTRL);                 

        /* Save off input corner */
        ox = rubber->g_x; oy = rubber->g_y;     
        /* Initialize mouse posn */
        graf_mkstate(&mx, &my, &foo, &foo);     

        do {    /* Choose UL corner      */
                rubber->g_x = min(ox, mx);      
                rubber->g_y = min(oy, my);
                rubber->g_w = max(ox, mx) -
                              rubber->g_x + 1;
                rubber->g_h = max(oy, my) -
                              rubber->g_y + 1;
                /* Lock into limit rect  */
                rc_intersect(limit, rubber);
                down = rub_wait(vdi_handle, rubber,
                                &mx, &my);
                } while (down);

        wind_update(END_MCTRL); /* Release mouse to GEM  */
        }

/*------------------------------*/
/*      hot_dragbox             */
/*------------------------------*/
        WORD
hot_dragbox(vdi_handle, box, limit, tree)
        WORD    vdi_handle;
        GRECT   *box, *limit;
        OBJECT  *tree;
        {
        UWORD   ox, oy, mx, my, foo, down;
        WORD    hover_obj, ret_obj;

        /* Set VDI modes for box */
        vswr_mode(vdi_handle, MD_XOR);          
        vsl_color(vdi_handle, BLACK);
        /* Capture mouse         */
        wind_update(BEG_MCTRL);                 

        /* Initialize mouse posn */
        graf_mkstate(&mx, &my, &foo, &foo);
        ox = min(box->g_w, max(0, mx - box->g_x) );
        oy = min(box->g_h, max(0, my - box->g_y) );
        hover_obj = NIL;

        do {
                box->g_x = mx - ox;
                box->g_y = my - oy;
                /* Lock into limit rect  */
                rc_constrain(limit, box);

                down = rub_wait(vdi_handle, box, &mx, &my);

                if (!inside(mx, my, limit))
                        ret_obj = NIL;
                else
                        {
                        ret_obj = objc_find(tree, ROOT, NIL,
                                            mx, my);
                        if (ret_obj != NIL)
                        if ( !(SELECTABLE &
                              (tree + ret_obj)->ob_flags) )
                                ret_obj = NIL;
                        }

                if (ret_obj != hover_obj)
                        {
                        if (hover_obj != NIL)
                                objc_toggle(tree, hover_obj);
                        hover_obj = ret_obj;
                        if (hover_obj != NIL)
                                objc_toggle(tree, hover_obj);
                        }
                } while (down);


        wind_update(END_MCTRL); /* Release mouse to GEM  */
        if (hover_obj != NIL)
                objc_toggle(tree, hover_obj);
        return (hover_obj);
        }

/*------------------------------*/
/*      rub_wait                */
/*------------------------------*/
        WORD
rub_wait(vdi_handle, box, mx, my)
        WORD    vdi_handle;
        GRECT   *box;
        WORD    *mx, *my;
        {
        WORD    which, kr;
        WORD    mb, ks, br; /* Not used, but needed */

        graf_mouse(M_OFF, 0x0L);
        vdi_xbox(vdi_handle, box); /* Draw waiting box */
        graf_mouse(M_ON, 0x0L);

        which = evnt_multi(MU_BUTTON | MU_M1,
                0x01, 0x01, 0x00,    /* Wait for button up */
                TRUE, *mx, *my, 1, 1,/* or mouse move      */
                0, 0, 0, 0, 0,
                0L, 
                0, 0,
                mx, my, &mb, &ks, &kr, &br);

        graf_mouse(M_OFF, 0x0L);
        vdi_xbox(vdi_handle, box); /* Take down waiting box */
        graf_mouse(M_ON, 0x0L);

        return (!(which & MU_BUTTON)); /* TRUE if still dragging */
        }

>>>>>>>>>>>>>>>>> Box Mover Utilities <<<<<<<<<<<<<<<<<<<<

        VOID
objc_toggle(tree, obj)
        OBJECT  *tree;
        WORD    obj;
        {
        WORD    state, newstate;
        GRECT   root, ob_rect;

        objc_xywh(tree, ROOT, &root);
        newstate = (tree + obj)->ob_state ^ SELECTED;
        objc_change(tree, obj, 0, root.g_x, root.g_y, 
                root.g_w, root.g_h, newstate, 1);
        }

        VOID
vdi_xbox(vdi_handle, pt)
        WORD    vdi_handle;
        GRECT   *pt;
        {
        WORD    pxy[10];

        vdi_bxpts(pt, pxy);
        vdi_xline(vdi_handle, 5, pxy);
        }

        VOID
vdi_bxpts(pt, pxy)
        GRECT   *pt;
        WORD    *pxy;
        {
        pxy[0] = pt->g_x;
        pxy[1] = pt->g_y;
        pxy[2] = pt->g_x + pt->g_w - 1;
        pxy[3] = pt->g_y;
        pxy[4] = pt->g_x + pt->g_w - 1;
        pxy[5] = pt->g_y + pt->g_h - 1;
        pxy[6] = pt->g_x;
        pxy[7] = pt->g_y + pt->g_h - 1;
        pxy[8] = pt->g_x;
        pxy[9] = pt->g_y;
        }

MLOCAL  WORD    hztltbl[2] = { 0x5555, 0xaaaa };
MLOCAL  WORD    verttbl[4] = { 0x5555, 0xaaaa, 0xaaaa, 0x5555 };

        VOID
vdi_xline(vdi_handle, ptscount, ppoints)
        WORD    vdi_handle, ptscount, *ppoints;
        {
        WORD            *linexy,i;
        WORD            st;

        for ( i = 1; i < ptscount; i++ )
                {
                if ( *ppoints == *(ppoints + 2) )
                        {
                        st = verttbl[( (( *ppoints) & 1) | 
                                ((*(ppoints + 1) & 1 ) << 1))];
                        }       
                else
                        {
                        linexy = ( *ppoints < *( ppoints + 2 ))
                                 ? ppoints 
                                 : ppoints + 2;
                        st = hztltbl[( *(linexy + 1) & 1)];
                        }

                vsl_udsty(vdi_handle, st);
                vsl_type(vdi_handle, 7);
                v_pline(vdi_handle, 2, ppoints);
                ppoints += 2;
                }

        vsl_type(vdi_handle, 1);
        }       


/* compute intersect of two rectangles  */

        WORD
rc_intersect(p1, p2)
        GRECT   *p1, *p2;
        {
        WORD    tx, ty, tw, th;

        tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w);
        th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h);
        tx = max(p2->g_x, p1->g_x);
        ty = max(p2->g_y, p1->g_y);
        p2->g_x = tx;
        p2->g_y = ty;
        p2->g_w = tw - tx;
        p2->g_h = th - ty;
        return( (tw > tx) && (th > ty) );
        }

        VOID
rc_union(p1, p2)
        GRECT           *p1, *p2;
        {
        WORD            tx, ty, tw, th;

        tw = max(p1->g_x + p1->g_w, p2->g_x + p2->g_w);
        th = max(p1->g_y + p1->g_h, p2->g_y + p2->g_h);
        tx = min(p1->g_x, p2->g_x);
        ty = min(p1->g_y, p2->g_y);
        p2->g_x = tx;
        p2->g_y = ty;
        p2->g_w = tw - tx;
        p2->g_h = th - ty;
        }

        VOID
rc_constrain(pc, pt)
        GRECT           *pc;
        GRECT           *pt;
        {
        if (pt->g_x < pc->g_x)
                pt->g_x = pc->g_x;
        if (pt->g_y < pc->g_y)
                pt->g_y = pc->g_y;
        if ((pt->g_x + pt->g_w) > (pc->g_x + pc->g_w))
                pt->g_x = (pc->g_x + pc->g_w) - pt->g_w;
        if ((pt->g_y + pt->g_h) > (pc->g_y + pc->g_h))
                pt->g_y = (pc->g_y + pc->g_h) - pt->g_h;
        }


/* determine if x,y is in rectangle     */

        BOOLEAN
inside(x, y, pt)
        UWORD           x, y;
        GRECT           *pt;
        {
        if ( (x >= pt->g_x) &&
             (y >= pt->g_y) &&
             (x < pt->g_x + pt->g_w) &&
             (y < pt->g_y + pt->g_h) )
                return(TRUE);
        else
                return(FALSE);
        } /* inside */

\end{verbatim}
\newpage

\subsubsection{\tt gmcl16.h}
\begin{verbatim} 

#define PROGRESS 0 /* TREE */
#define PLINE 2    /* OBJECT in TREE #0 */
#define PROBOX 3   /* OBJECT in TREE #0 */
#define PROBAR 4   /* OBJECT in TREE #0 */
#define STRINGS 1  /* TREE */
#define P1 1       /* OBJECT in TREE #1 */
#define P2 2       /* OBJECT in TREE #1 */
#define PN 3       /* OBJECT in TREE #1 */
\end{verbatim}
\newpage

\subsubsection{\tt gmcl16.rsh}
\begin{verbatim} 

#define T0OBJ 0
#define T1OBJ 5
#define FREEBB 0
#define FREEIMG 0
#define FREESTR 7

BYTE *rs_strings[] = {
"Sample Progress Box",
"Variable Text Line",
"",
"",
"Progress Event One",
"Progress Event Two",
"Progress Event N"};

LONG rs_frstr[] = {
0};

BITBLK rs_bitblk[] = {
0};

LONG rs_frimg[] = {
0};

ICONBLK rs_iconblk[] = {
0};

TEDINFO rs_tedinfo[] = {
1L, 2L, 3L, 3, 6, 2, 0x1380, 0x0, -1, 19,1};

OBJECT rs_object[] = {
-1, 1, 3, G_BOX, NONE, OUTLINED, 0x21100L, 0,0, 41,8,
2, -1, -1, G_STRING, NONE, NORMAL, 0x0L, 11,1, 19,1,
3, -1, -1, G_TEXT, NONE, NORMAL, 0x0L, 0,3, 41,1,
0, 4, 4, G_BOX, NONE, NORMAL, 0xFF1170L, 3,5, 34,1,
3, -1, -1, G_BOX, LASTOB, NORMAL, 0xFF1172L, 0,0, 6,1,
-1, 1, 3, G_BOX, NONE, OUTLINED, 0x21100L, 0,0, 27,7,
2, -1, -1, G_STRING, NONE, NORMAL, 0x4L, 2,1, 18,1,
3, -1, -1, G_STRING, NONE, NORMAL, 0x5L, 2,3, 18,1,
0, -1, -1, G_STRING, LASTOB, NORMAL, 0x6L, 2,5, 18,1};

LONG rs_trindex[] = {
0L,
5L};

struct foobar {
        WORD    dummy;
        WORD    *image;
        } rs_imdope[] = {
0};

#define NUM_STRINGS 7
#define NUM_FRSTR 0
#define NUM_IMAGES 0
#define NUM_BB 0
#define NUM_FRIMG 0
#define NUM_IB 0
#define NUM_TI 1
#define NUM_OBS 9
#define NUM_TREE 2

BYTE pname[] = "GMCL16.RSC"
\end{verbatim}

\newpage

% End of Appendix B
